package com.backend.modules.system.service.impl;

import com.backend.common.enums.DeptType;
import com.backend.common.enums.UserType;
import com.backend.common.exception.BusinessException;
import com.backend.modules.system.dto.TeacherDTO;
import com.backend.modules.system.dto.TeacherQueryDTO;
import com.backend.modules.system.entity.SysDepartment;
import com.backend.modules.system.entity.SysTeacherClass;
import com.backend.modules.system.entity.SysUser;
import com.backend.modules.system.repository.SysTeacherClassRepository;
import com.backend.modules.system.repository.SysUserRepository;
import com.backend.modules.system.service.SysDepartmentService;
import com.backend.modules.system.service.TeacherService;
import lombok.RequiredArgsConstructor;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import javax.persistence.criteria.Subquery;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

@Service
@RequiredArgsConstructor
public class TeacherServiceImpl implements TeacherService {

    private final SysUserRepository userRepository;
    private final SysTeacherClassRepository teacherClassRepository;
    private final SysDepartmentService departmentService;
    private final PasswordEncoder passwordEncoder;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void create(TeacherDTO dto) {
        // 校验工号是否存在
        if (userRepository.existsByUserCode(dto.getUserCode())) {
            throw new BusinessException("工号已存在");
        }
        
        // 校验班级是否存在且类型是否正确
        List<SysDepartment> classes = new ArrayList<>();
        if (dto.getClassIds() != null && !dto.getClassIds().isEmpty()) {
            classes = dto.getClassIds().stream()
                    .map(id -> {
                        SysDepartment dept = departmentService.getById(id);
                        if (!DeptType.CLASS.getValue().equals(dept.getType())) {
                            throw new BusinessException("只能选择班级");
                        }
                        return dept;
                    })
                    .collect(Collectors.toList());
        }
        
        // 创建教师用户
        SysUser user = new SysUser();
        user.setUserCode(dto.getUserCode());
        user.setUsername(dto.getUserCode());
        user.setPassword(passwordEncoder.encode(dto.getUserCode()));
        user.setRealName(dto.getRealName());
        user.setPhone(dto.getPhone());
        user.setEmail(dto.getEmail());
        user.setPosition(dto.getPosition());
        user.setUserType(UserType.TEACHER.getValue());
        user.setStatus(true);
        user.setGender(dto.getGender());
        
        userRepository.save(user);
        
        // 保存教师班级关联
        if (!classes.isEmpty()) {
            List<SysTeacherClass> teacherClasses = classes.stream()
                    .map(clazz -> {
                        SysTeacherClass tc = new SysTeacherClass();
                        tc.setTeacher(user);
                        tc.setClazz(clazz);
                        return tc;
                    })
                    .collect(Collectors.toList());
            
            teacherClassRepository.saveAll(teacherClasses);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void update(Long id, TeacherDTO dto) {
        SysUser user = getById(id);
        
        // 校验班级是否存在且类型是否正确
        List<SysDepartment> classes = new ArrayList<>();
        if (dto.getClassIds() != null && !dto.getClassIds().isEmpty()) {
            classes = dto.getClassIds().stream()
                    .map(classId -> {
                        SysDepartment dept = departmentService.getById(classId);
                        if (!DeptType.CLASS.getValue().equals(dept.getType())) {
                            throw new BusinessException("只能选择班级");
                        }
                        return dept;
                    })
                    .collect(Collectors.toList());
        }
        
        // 更新教师信息
        user.setRealName(dto.getRealName());
        user.setPhone(dto.getPhone());
        user.setEmail(dto.getEmail());
        user.setPosition(dto.getPosition());
        user.setGender(dto.getGender());
        
        userRepository.save(user);
        
        // 更新教师班级关联
        teacherClassRepository.deleteByTeacherId(id);
        if (!classes.isEmpty()) {
            List<SysTeacherClass> teacherClasses = classes.stream()
                    .map(clazz -> {
                        SysTeacherClass tc = new SysTeacherClass();
                        tc.setTeacher(user);
                        tc.setClazz(clazz);
                        return tc;
                    })
                    .collect(Collectors.toList());
            
            teacherClassRepository.saveAll(teacherClasses);
        }
    }

    @Override
    public Page<SysUser> page(TeacherQueryDTO query, Pageable pageable) {
        Specification<SysUser> spec = (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = new ArrayList<>();
            
            // 只查询教师
            predicates.add(criteriaBuilder.equal(root.get("userType"), UserType.TEACHER.getValue()));
            
            // 工号
            if (StringUtils.hasText(query.getUserCode())) {
                predicates.add(criteriaBuilder.like(root.get("userCode"), 
                        "%" + query.getUserCode() + "%"));
            }
            
            // 姓名
            if (StringUtils.hasText(query.getRealName())) {
                predicates.add(criteriaBuilder.like(root.get("realName"), 
                        "%" + query.getRealName() + "%"));
            }
            
            // 手机号
            if (StringUtils.hasText(query.getPhone())) {
                predicates.add(criteriaBuilder.like(root.get("phone"), 
                        "%" + query.getPhone() + "%"));
            }
            
            // 按班级查询
            if (query.getClassIds() != null && !query.getClassIds().isEmpty()) {
                Subquery<Long> subquery = criteriaQuery.subquery(Long.class);
                Root<SysTeacherClass> teacherClass = subquery.from(SysTeacherClass.class);
                subquery.select(teacherClass.get("teacherId"))
                        .where(teacherClass.get("classId").in(query.getClassIds()));
                
                predicates.add(root.get("id").in(subquery));
            }
            
            // 职位
            if (StringUtils.hasText(query.getPosition())) {
                predicates.add(criteriaBuilder.like(root.get("position"), 
                        "%" + query.getPosition() + "%"));
            }
            return criteriaBuilder.and(predicates.toArray(new Predicate[0]));
        };
        
        return userRepository.findAll(spec, pageable);
    }

    @Override
    public SysUser getById(Long id) {
        SysUser user = userRepository.findById(id)
                .orElseThrow(() -> new BusinessException("用户不存在"));
        
        // 校验是否为教师
        if (!UserType.TEACHER.getValue().equals(user.getUserType())) {
            throw new BusinessException("用户不是教师");
        }
        
        return user;
    }

    @Override
    public List<SysDepartment> getTeacherClasses(Long teacherId) {
        List<Long> classIds = teacherClassRepository.findClassIdsByTeacherId(teacherId);
        if (classIds.isEmpty()) {
            return new ArrayList<>();
        }
        return classIds.stream()
                .map(departmentService::getById)
                .collect(Collectors.toList());
    }

    @Override
    public List<SysDepartment> getAvailableClasses(Long majorId) {
        // 如果指定了专业ID，则只返回该专业下的班级
        if (majorId != null) {
            SysDepartment major = departmentService.getById(majorId);
            if (!DeptType.MAJOR.getValue().equals(major.getType())) {
                throw new BusinessException("只能选择专业");
            }
            return major.getChildren();
        }
        
        // 否则返回所有班级
        return departmentService.list(null).stream()
                .filter(dept -> DeptType.CLASS.getValue().equals(dept.getType()))
                .collect(Collectors.toList());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void delete(Long id) {
        SysUser user = getById(id);

        List<SysTeacherClass> teacherClasses = user.getTeacherClasses();
        if (!teacherClasses.isEmpty()) {
            List<Long> collect = teacherClasses.stream().map(SysTeacherClass::getId)
                .toList();
            teacherClassRepository.deleteByClassIdIn(collect);
        }
        // 删除教师
        userRepository.delete(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateStatus(Long id, Boolean status) {
        SysUser user = getById(id);
        user.setStatus(status);
        userRepository.save(user);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resetPassword(Long id) {
        SysUser user = getById(id);
        // 重置密码为工号
        user.setPassword(passwordEncoder.encode(user.getUserCode()));
        userRepository.save(user);
    }
} 